﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TableParsers;

namespace SpeakupTests.WebLayer.ClassTypes
{
    [TestClass]
    public class ClassNameTests
    {
        string RandomString(Random rnd, int len)
        {
            StringBuilder builder = new StringBuilder();

            for(int i =0; i < len; i++)
            {
                builder.Append(rnd.Next() % ('z' - 'a') + 'a');
            }
            return builder.ToString();            
        }

        [TestMethod]
        public void CreateClassName()
        {
            Dictionary<ClassType, ClassKind> TypeToKind =  new Dictionary<ClassType,ClassKind>();

            TypeToKind[ClassType.Club] =  ClassKind.Club;
            TypeToKind[ClassType.Business] = ClassKind.Bussiness;
            TypeToKind[ClassType.Group] = ClassKind.Group;
            TypeToKind[ClassType.Conversation] =  ClassKind.Workshop;
            TypeToKind[ClassType.Grammar] = ClassKind.Workshop;
            TypeToKind[ClassType.Reading] = ClassKind.Workshop;
            TypeToKind[ClassType.Writing] = ClassKind.Workshop;
            TypeToKind[ClassType.FirstClass] = ClassKind.Management;
            TypeToKind[ClassType.ProgressFollowup] = ClassKind.Management;
            TypeToKind[ClassType.Unknown] = ClassKind.Unknown;            

            foreach (ClassType cnType in Enum.GetValues(typeof(ClassType)))
            {
                ClassName cn = new ClassName("", "", cnType);
                Assert.AreEqual(cnType, cn.Type);
                Assert.AreEqual(TypeToKind[cnType], cn.Kind);
            }

            Random rnd = new Random();
            for (int i = 0; i < 10; i++)
            {
                string fullName = RandomString(rnd, 10);
                ClassName cn = new ClassName(fullName, "", ClassType.Club);

                Assert.AreEqual(fullName, cn.FullName);
            }

            for (int i = 0; i < 10; i++)
            {
                string name = RandomString(rnd, 10);
                ClassName cn = new ClassName("", name, ClassType.Club);

                Assert.AreEqual(name, cn.Name);
            }
        }

        [TestMethod]
        public void ClassNameEqualsAsObject()
        {
            //equality with null
            Object obj = new ClassName("", "", ClassType.Club);
            Assert.IsFalse(obj.Equals(null));

            //equality with other object
            int i = 10;
            Assert.IsFalse(obj.Equals(i));

            //equality with itself
            Assert.IsTrue(obj.Equals(obj));

            //all members are assigned the same values
            Object objLeft = new ClassName("FullName", "Name", ClassType.Club);
            Object objRight = new ClassName("FullName", "Name", ClassType.Club);

            Assert.IsTrue(objLeft.Equals(objRight));
            Assert.IsTrue(objRight.Equals(objLeft));

            //full names are different, but thName and class type is the same
            objLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            objRight = new ClassName("FullName_2", "Name", ClassType.Club);

            Assert.IsTrue(objLeft.Equals(objRight));
            Assert.IsTrue(objRight.Equals(objLeft));

            //Names are different
            objLeft = new ClassName("FullName_1", "Name_1", ClassType.Club);
            objRight = new ClassName("FullName_2", "Name_2", ClassType.Club);

            Assert.IsFalse(objLeft.Equals(objRight));
            Assert.IsFalse(objRight.Equals(objLeft));

            //ClassTypes are different
            objLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            objRight = new ClassName("FullName_2", "Name", ClassType.Conversation);

            Assert.IsFalse(objLeft.Equals(objRight));
            Assert.IsFalse(objRight.Equals(objLeft));
        }

        [TestMethod]
        public void ClassNameEquals()
        {
            //equality with null
            ClassName cn = new ClassName("", "", ClassType.Club);
            ClassName nullCn = null;
            Assert.IsFalse(cn.Equals(nullCn));

            //equality with itself
            Assert.IsTrue(cn.Equals(cn));

            //all members are assigned the same values
            ClassName cnLeft = new ClassName("FullName", "Name", ClassType.Club);
            ClassName cnRight = new ClassName("FullName", "Name", ClassType.Club);

            Assert.IsTrue(cnLeft.Equals(cnRight));
            Assert.IsTrue(cnRight.Equals(cnLeft));

            //full names are different, but thName and class type is the same
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Club);

            Assert.IsTrue(cnLeft.Equals(cnRight));
            Assert.IsTrue(cnRight.Equals(cnLeft));

            //Names are different
            cnLeft = new ClassName("FullName_1", "Name_1", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name_2", ClassType.Club);

            Assert.IsFalse(cnLeft.Equals(cnRight));
            Assert.IsFalse(cnRight.Equals(cnLeft));

            //ClassTypes are different
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Conversation);

            Assert.IsFalse(cnLeft.Equals(cnRight));
            Assert.IsFalse(cnRight.Equals(cnLeft));
        }

        [TestMethod]
        public void ClassNameGetHashCode()
        {
            //all members are assigned the same values
            ClassName cnLeft = new ClassName("FullName", "Name", ClassType.Club);
            ClassName cnRight = new ClassName("FullName", "Name", ClassType.Club);

            Assert.AreEqual(cnLeft.GetHashCode(), cnRight.GetHashCode());            

            //full names are different, but thName and class type is the same
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Club);

            Assert.AreEqual(cnLeft.GetHashCode(), cnRight.GetHashCode());                        

            //Names are different
            cnLeft = new ClassName("FullName_1", "Name_1", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name_2", ClassType.Club);

            Assert.AreNotEqual(cnLeft.GetHashCode(), cnRight.GetHashCode());

            //ClassTypes are different
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Conversation);

            Assert.AreNotEqual(cnLeft.GetHashCode(), cnRight.GetHashCode());
        }

        [TestMethod]
        public void ClassNameCompareTo()
        {
            //all members are assigned the same values
            ClassName cnLeft = new ClassName("FullName", "Name", ClassType.Club);
            ClassName cnRight = new ClassName("FullName", "Name", ClassType.Club);            

            Assert.AreEqual(0, cnLeft.CompareTo(cnRight));
            Assert.AreEqual(0, cnRight.CompareTo(cnLeft));
            
            //full names are different, but thName and class type is the same
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Club);

            Assert.AreEqual(0, cnLeft.CompareTo(cnRight));
            Assert.AreEqual(0, cnRight.CompareTo(cnLeft));

            //Names are different
            cnLeft = new ClassName("FullName_1", "Name_1", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name_2", ClassType.Club);

            Assert.AreEqual(Math.Sign(cnLeft.Name.CompareTo(cnRight.Name)), 
                            Math.Sign(cnLeft.CompareTo(cnRight))            );

            Assert.AreEqual(Math.Sign(cnRight.Name.CompareTo(cnLeft.Name)),
                            Math.Sign(cnRight.CompareTo(cnLeft)));

            //ClassTypes are different
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Conversation);

            Assert.AreEqual(Math.Sign(cnLeft.Type.CompareTo(cnRight.Type)),
                            Math.Sign(cnLeft.CompareTo(cnRight)));

            Assert.AreEqual(Math.Sign(cnRight.Type.CompareTo(cnLeft.Type)),
                            Math.Sign(cnRight.CompareTo(cnLeft)));
        }

        [TestMethod]
        public void ClassNameOperators()
        {
            ClassName cnLeft = null;
            ClassName cnRight = null;

            Assert.IsTrue(cnLeft == cnRight);
            Assert.IsFalse(cnLeft != cnRight);

            cnLeft = null;
            cnRight = new ClassName("FullName", "Name", ClassType.Club);

            Assert.IsFalse(cnLeft == cnRight);
            Assert.IsFalse(cnRight == cnLeft);
            Assert.IsTrue(cnLeft != cnRight);
            Assert.IsTrue(cnRight != cnLeft);
            
            //all members are assigned the same values
            cnLeft = new ClassName("FullName", "Name", ClassType.Club);
            cnRight = new ClassName("FullName", "Name", ClassType.Club);

            Assert.IsTrue(cnLeft == cnRight);
            Assert.IsTrue(cnRight == cnLeft);

            Assert.IsFalse(cnLeft != cnRight);
            Assert.IsFalse(cnRight != cnLeft);

            Assert.IsFalse(cnLeft < cnRight);
            Assert.IsFalse(cnRight < cnLeft);

            Assert.IsTrue(cnLeft <= cnRight);
            Assert.IsTrue(cnRight <= cnLeft);

            Assert.IsFalse(cnLeft > cnRight);
            Assert.IsFalse(cnRight > cnLeft);

            Assert.IsTrue(cnLeft >= cnRight);
            Assert.IsTrue(cnRight >= cnLeft);


            //full names are different, but thName and class type is the same
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Club);

            Assert.IsTrue(cnLeft == cnRight);
            Assert.IsTrue(cnRight == cnLeft);

            Assert.IsFalse(cnLeft != cnRight);
            Assert.IsFalse(cnRight != cnLeft);

            Assert.IsFalse(cnLeft < cnRight);
            Assert.IsFalse(cnRight < cnLeft);

            Assert.IsTrue(cnLeft <= cnRight);
            Assert.IsTrue(cnRight <= cnLeft);

            Assert.IsFalse(cnLeft > cnRight);
            Assert.IsFalse(cnRight > cnLeft);

            Assert.IsTrue(cnLeft >= cnRight);
            Assert.IsTrue(cnRight >= cnLeft);

            //Names are different
            cnLeft = new ClassName("FullName_1", "Name_1", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name_2", ClassType.Club);

            Assert.IsFalse(cnLeft == cnRight);
            Assert.IsFalse(cnRight == cnLeft);

            Assert.IsTrue(cnLeft != cnRight);
            Assert.IsTrue(cnRight != cnLeft);

            Assert.AreEqual( cnLeft.Name.CompareTo(cnRight.Name) < 0, cnLeft < cnRight);
            Assert.AreEqual( cnRight.Name.CompareTo(cnLeft.Name) < 0, cnRight < cnLeft);

            Assert.AreEqual(cnLeft.Name.CompareTo(cnRight.Name) <= 0, cnLeft <= cnRight);
            Assert.AreEqual(cnRight.Name.CompareTo(cnLeft.Name) <= 0, cnRight <= cnLeft);

            Assert.AreEqual(cnLeft.Name.CompareTo(cnRight.Name) > 0, cnLeft > cnRight);
            Assert.AreEqual(cnRight.Name.CompareTo(cnLeft.Name) > 0, cnRight > cnLeft);

            Assert.AreEqual(cnLeft.Name.CompareTo(cnRight.Name) >= 0, cnLeft >= cnRight);
            Assert.AreEqual(cnRight.Name.CompareTo(cnLeft.Name) >= 0, cnRight >= cnLeft);
          
            //ClassTypes are different
            cnLeft = new ClassName("FullName_1", "Name", ClassType.Club);
            cnRight = new ClassName("FullName_2", "Name", ClassType.Conversation);

            Assert.IsFalse(cnLeft == cnRight);
            Assert.IsFalse(cnRight == cnLeft);

            Assert.IsTrue(cnLeft != cnRight);
            Assert.IsTrue(cnRight != cnLeft);

            Assert.AreEqual(cnLeft.Type < cnRight.Type, cnLeft < cnRight);
            Assert.AreEqual(cnRight.Type < cnLeft.Type, cnRight < cnLeft);

            Assert.AreEqual(cnLeft.Type <= cnRight.Type, cnLeft <= cnRight);
            Assert.AreEqual(cnRight.Type <= cnLeft.Type, cnRight <= cnLeft);

            Assert.AreEqual(cnLeft.Type > cnRight.Type, cnLeft > cnRight);
            Assert.AreEqual(cnRight.Type > cnLeft.Type, cnRight > cnLeft);

            Assert.AreEqual(cnLeft.Type >= cnRight.Type, cnLeft >= cnRight);
            Assert.AreEqual(cnRight.Type >= cnLeft.Type, cnRight >= cnLeft);
        }
    }
}
